//#include <iostream>
//// 泛型编程
////模板的原理是什么，需要什么
//// 编译器帮助你实例化你要的函数和类
//template<typename T>
//void Swap(T& left, T& right)
//{
//	T temp = left;
//	left = right;
//	right = temp;
//}
//int main()
//{
//	//三个调用的不是一个函数
//	int a = 0, b = 1;
//	Swap(a, b);
//
//	double c = 1.1,d = 2.2;
//	Swap(c, d);
//
//	int* p1 = &a, * p2 = &b;
//	Swap(p1, p2);
//
//	return 0;
//}



//// —————————————— 函数实例化
//#include <iostream>
//using namespace std;
////template<typename T> 
//template<class T> //上下两者差不多
//T Add(const T& left, const T& right)
//{
//	cout << "T Add(const T& left, const T& right)" << endl;
//	return left + right;
//}
//
//template<typename T1,typename T2>
//auto Add(const T1& left, const T2& right)
//{
//
//	cout << "auto Add(const T1& left, const T2& right)" << endl;
//	return left + right;
//} 
//
//int main()
//{
//	int a1 = 10, a2 = 20;
//	double d1 = 10.1, d2 = 20.2;
//	Add(a1, a2);
//	Add(d1, d2);
//	
//	// Add(a1, d2);
//	/*
//    该语句不能通过编译，因为在编译期间，当编译器看到该实例化时，需要推演其实参类型
//    通过实参a1将T推演为int，通过实参d1将T推演为double类型，但模板参数列表中只有一个T，
//    编译器无法确定此处到底该将T确定为int 或者 double类型而报错
//注意：在模板中，编译器一般不会进行类型转换操作，因为一旦转化出问题，编译器就需要背黑锅
//     Add(a1, d1);
//*/
//// 此时有两种处理方式：1. 用户自己来强制转化 2. 使用显式实例化
//	//用户自己来强制转化
//	cout<<Add(a1, (int)d2) << endl;
//	cout << Add((double)a1,d2) << endl;
//
//	////使用显式实例化，不再让你推演参数
//	//cout<<Add<int>(a1, d2)<< endl;
//	//cout << Add<double>(a1, d2) << endl;
//
// 
//	cout << Add<int, double> (a1, d2) << endl;
//	cout << Add<int, double>(a1, d2) << endl;
//
//	cout << Add(a1, d2) << endl;
//
//	return 0;
//}


// —————————————— 
//#include <iostream>
//using namespace std;
//
//class A
//{
//public:
//	A(int a = 0)
//		: _a(a)
//	{
//		cout << "A():" << this << endl;
//	}
//	~A()
//	{
//		cout << "~A()" << this << endl;
//	}
//private:
//	int _a;
//};
//
//template<class T>
//T* func(int a)
//{
//	T* p = (T*)operator new(sizeof(T));
//	new(P)T(a);
//
//	return p;
//}
//
//int main()
//{
//	//A* ret = func(1);
//	int*ret =func<int>(1);
//	A* ret = func<A>(1);
//
//	return  0;
//}



#include <iostream>
using namespace std;

// 专门处理int的加法函数
auto Add(int left, int right) //成品
{
	cout << "auto Add(int left, int right)" << endl;
	return left + right;
}

// 通用加法函数
template<class T1, class T2> 
auto Add(T1 left, T2 right) //半成品
{
	cout << "auto Add(T1 left, T2 right)" << endl;
	return left + right;
}

template<typename T>
T Add(const T& left, const T& right)
{
	cout << "T Add(const T& left, const T& right)" << endl;
	return left + right;
}

// 
// 1、都有的情况下，先匹配普通函数 + 参数匹配（成品 + 口味对）
// 2、没有普通函数，优先函数模板 + 匹配参数匹配（半成品 + 口味对）
// 3、只有一个，类型转换一下也能用，也可以匹配调用（口味不对，将就一下） 
int main()
{
	Add(1, 2);     // 与非函数模板类型完全匹配，不需要函数模板实例化
	Add(1.1, 2.2); //与非函数模板类型完全匹配，不需要函数模板实例化
	
	Add(1, 2.0);   // 模板函数可以生成更加匹配的版本，编译器根据实参生成更加匹配的Add函数

	return 0;
}

